package com.generator.template.utils;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

public class DateTimeUtil {
    /**
     * 当前时间，转换为{@link Date}对象
     *
     * @return 当前时间
     */
    public static Date date() {
        return new Date();
    }

    /**
     * Long类型时间转为{@link Date}<br>
     * 只支持毫秒级别时间戳，如果需要秒级别时间戳，请自行×1000
     *
     * @param date Long类型Date（Unix时间戳）
     * @return 时间对象
     */
    public static Date date(long date) {
        return new Date(date);
    }

    /**
     * 当前时间的时间戳
     *
     * @return 时间
     */
    public static long current() {
        return System.currentTimeMillis();
    }

    /**
     * 当前时间，格式 yyyy-MM-dd HH:mm:ss
     *
     * @return 当前时间的标准形式字符串
     */
    public static String now() {
        return DateUtil.now();
    }

    /**
     * 当前日期，格式 yyyy-MM-dd
     *
     * @return 当前日期的标准形式字符串
     */
    public static String today() {
        return DateUtil.today();
    }

    /**
     * 某天日期，格式yyyy-MM-dd
     * @param date date
     * @return 某天日期的标准形式字符串
     */
    public static String day(Date date) {
        return DateUtil.formatDate(date);
    }

    /**
     * 昨日日期，格式 yyyy-MM-dd
     *
     * @return 昨日日期的标准形式字符串
     */
    public static String yesterday() {
        return DateUtil.yesterday().toDateStr();
    }

    /**
     * 昨日日期，转换为Date对象
     * @return 昨日日期的Date格式
     */
    public static Date dateOfYesterday() {
        return DateUtil.yesterday().toJdkDate();
    }

    /**
     * 根据特定格式格式化日期
     *
     * @param date   被格式化的日期
     * @param format 日期格式
     * @return 格式化后的字符串
     */
    public static String format(Date date, String format) {
        return DateUtil.format(date, format);
    }

    /**
     * 格式化日期时间<br>
     * 格式 yyyy-MM-dd HH:mm:ss
     *
     * @param date 被格式化的日期
     * @return 格式化后的日期
     */
    public static String formatDateTime(Date date) {
        return DateUtil.formatDateTime(date);
    }

    /**
     * 格式化日期部分（不包括时间）<br>
     * 格式 yyyy-MM-dd
     *
     * @param date 被格式化的日期
     * @return 格式化后的字符串
     */
    public static String formatDate(Date date) {
        return DateUtil.formatDate(date);
    }

    /**
     * 格式化时间<br>
     * 格式 HH:mm:ss
     *
     * @param date 被格式化的日期
     * @return 格式化后的字符串
     * @since 3.0.1
     */
    public static String formatTime(Date date) {
        return DateUtil.formatTime(date);
    }

    /**
     * 将日期字符串转换为{@link Date}对象，该方法会自动识别一些常用格式，格式：<br>
     * <ol>
     * <li>yyyy-MM-dd HH:mm:ss</li>
     * <li>yyyy/MM/dd HH:mm:ss</li>
     * <li>yyyy.MM.dd HH:mm:ss</li>
     * <li>yyyy年MM月dd日 HH时mm分ss秒</li>
     * <li>yyyy-MM-dd</li>
     * <li>yyyy/MM/dd</li>
     * <li>yyyy.MM.dd</li>
     * <li>HH:mm:ss</li>
     * <li>HH时mm分ss秒</li>
     * <li>yyyy-MM-dd HH:mm</li>
     * <li>yyyy-MM-dd HH:mm:ss.SSS</li>
     * <li>yyyyMMddHHmmss</li>
     * <li>yyyyMMddHHmmssSSS</li>
     * <li>yyyyMMdd</li>
     * <li>EEE, dd MMM yyyy HH:mm:ss z</li>
     * <li>EEE MMM dd HH:mm:ss zzz yyyy</li>
     * <li>yyyy-MM-dd'T'HH:mm:ss'Z'</li>
     * <li>yyyy-MM-dd'T'HH:mm:ss.SSS'Z'</li>
     * <li>yyyy-MM-dd'T'HH:mm:ssZ</li>
     * <li>yyyy-MM-dd'T'HH:mm:ss.SSSZ</li>
     * </ol>
     *
     * @param dateCharSequence 日期字符串
     * @return 日期
     */
    public static Date parse(CharSequence dateCharSequence) {
        return DateUtil.parse(dateCharSequence);
    }

    /**
     * 将特定格式的日期转换为Date对象
     *
     * @param dateStr 特定格式的日期
     * @param format  格式，例如yyyy-MM-dd @see com.minivision.maiot.common.base.utils.DatePattern
     * @return 日期对象
     */
    public static Date parse(CharSequence dateStr, String format) {
        return DateUtil.parse(dateStr, format);
    }

    /**
     * 获得年的部分
     *
     * @param date 日期
     * @return 年的部分
     */
    public static int year(Date date) {
        return DateUtil.year(date);
    }

    /**
     * 获得月份，从0开始计数
     *
     * @param date 日期
     * @return 月份，从0开始计数
     */
    public static int month(Date date) {
        return DateUtil.month(date);
    }

    /**
     * 获取小时，
     * Description: <br> 
     * @author zhangshuxing<br>
     * @taskId <br>
     * @param date 日期
     * @return <br>
     */
    public static int hour(Date date, boolean is24Hourclock) {
        return DateUtil.hour(date, is24Hourclock);
    }
    /**
     * 获得指定日期是所在年份的第几周<br>
     * 此方法返回值与一周的第一天有关，比如：<br>
     * 2016年1月3日为周日，如果一周的第一天为周日，那这天是第二周（返回2）<br>
     * 如果一周的第一天为周一，那这天是第一周（返回1）<br>
     * 跨年的那个星期得到的结果总是1
     *
     * @param date 日期
     * @return 周
     */
    public static int weekOfYear(Date date) {
        return DateUtil.weekOfYear(date);
    }

    /**
     * 获得指定日期是这个日期所在月份的第几天<br>
     *
     * @param date 日期
     * @return 天
     */
    public static int dayOfMonth(Date date) {
        return DateUtil.dayOfMonth(date);
    }

    /**
     * 获得指定日期是这个日期所在年的第几天
     *
     * @param date 日期
     * @return 天
     * @since 5.3.6
     */
    public static int dayOfYear(Date date) {
        return DateUtil.dayOfYear(date);
    }

    /**
     * 获取某天的开始时间
     *
     * @param date 日期
     * @return {@link Date}
     */
    public static Date beginOfDay(Date date) {
        return DateUtil.beginOfDay(date);
    }

    /**
     * 获取某天的结束时间
     *
     * @param date 日期
     * @return {@link Date}
     */
    public static Date endOfDay(Date date) {
        return DateUtil.endOfDay(date);
    }

    /**
     * 获取某周的开始时间，周一定为一周的开始时间
     *
     * @param date 日期
     * @return {@link Date}
     */
    public static Date beginOfWeek(Date date) {
        return DateUtil.beginOfWeek(date);
    }

    /**
     * 获取某周的开始时间
     *
     * @param date               日期
     * @param isMondayAsFirstDay 是否周一做为一周的第一天（false表示周日做为第一天）
     * @return {@link Date}
     * @since 5.4.0
     */
    public static Date beginOfWeek(Date date, boolean isMondayAsFirstDay) {
        return DateUtil.beginOfWeek(date, isMondayAsFirstDay);
    }

    /**
     * 获取某周的结束时间，周日定为一周的结束
     *
     * @param date 日期
     * @return {@link Date}
     */
    public static Date endOfWeek(Date date) {
        return DateUtil.endOfWeek(date);
    }

    /**
     * 获取某周的结束时间
     *
     * @param date              日期
     * @param isSundayAsLastDay 是否周日做为一周的最后一天（false表示周六做为最后一天）
     * @return {@link Date}
     * @since 5.4.0
     */
    public static Date endOfWeek(Date date, boolean isSundayAsLastDay) {
        return DateUtil.endOfWeek(date, isSundayAsLastDay);
    }

    /**
     * 获取某月的开始时间
     *
     * @param date 日期
     * @return {@link Date}
     */
    public static Date beginOfMonth(Date date) {
        return DateUtil.beginOfMonth(date);
    }

    /**
     * 获取某月的结束时间
     *
     * @param date 日期
     * @return {@link Date}
     */
    public static Date endOfMonth(Date date) {
        return DateUtil.endOfMonth(date);
    }

    /**
     * 获取某年的开始时间
     *
     * @param date 日期
     * @return {@link Date}
     */
    public static Date beginOfYear(Date date) {
        return DateUtil.beginOfYear(date);
    }

    /**
     * 获取某年的结束时间
     *
     * @param date 日期
     * @return {@link Date}
     */
    public static Date endOfYear(Date date) {
        return DateUtil.endOfYear(date);
    }

    /**
     * 获取指定日期偏移指定时间后的时间，生成的偏移日期不影响原日期
     *
     * @param date      基准日期
     * @param dateField 偏移的粒度大小（小时、天、月等）{@link DateField}
     * @param offset    偏移量，正数为向后偏移，负数为向前偏移
     * @return 偏移后的日期
     */
    public static Date offset(Date date, DateField dateField, int offset) {
        return DateUtil.offset(date, dateField, offset);
    }

    /**
     * 偏移秒数
     *
     * @param date   日期
     * @param offset 偏移秒数，正数向未来偏移，负数向历史偏移
     * @return 偏移后的日期
     */
    public static Date offsetSecond(Date date, int offset) {
        return DateUtil.offsetSecond(date, offset);
    }

    /**
     * 偏移分钟
     *
     * @param date   日期
     * @param offset 偏移分钟数，正数向未来偏移，负数向历史偏移
     * @return 偏移后的日期
     */
    public static Date offsetMinute(Date date, int offset) {
        return DateUtil.offsetMinute(date, offset);
    }

    /**
     * 偏移小时
     *
     * @param date   日期
     * @param offset 偏移小时数，正数向未来偏移，负数向历史偏移
     * @return 偏移后的日期
     */
    public static Date offsetHour(Date date, int offset) {
        return DateUtil.offsetMinute(date, offset);
    }

    /**
     * 偏移天
     *
     * @param date   日期
     * @param offset 偏移天数，正数向未来偏移，负数向历史偏移
     * @return 偏移后的日期
     */
    public static Date offsetDay(Date date, int offset) {
        return DateUtil.offsetDay(date, offset);
    }

    /**
     * 偏移周
     *
     * @param date   日期
     * @param offset 偏移周数，正数向未来偏移，负数向历史偏移
     * @return 偏移后的日期
     */
    public static Date offsetWeek(Date date, int offset) {
        return DateUtil.offsetWeek(date, offset);
    }

    /**
     * 偏移月
     *
     * @param date   日期
     * @param offset 偏移月数，正数向未来偏移，负数向历史偏移
     * @return 偏移后的日期
     */
    public static Date offsetMonth(Date date, int offset) {
        return DateUtil.offsetMonth(date, offset);
    }

    /**
     * 判断两个日期相差的时长，只保留绝对值
     *
     * @param beginDate 起始日期
     * @param endDate   结束日期
     * @param unit      相差的单位：相差 天{@link DateUnit#DAY}、小时{@link DateUnit#HOUR} 等
     * @return 日期差
     */
    public static long between(Date beginDate, Date endDate, DateUnit unit) {
        return DateUtil.between(beginDate, endDate, unit);
    }

    /**
     * 判断两个日期相差的时长
     *
     * @param beginDate 起始日期
     * @param endDate   结束日期
     * @param unit      相差的单位：相差 天{@link DateUnit#DAY}、小时{@link DateUnit#HOUR} 等
     * @param isAbs     日期间隔是否只保留绝对值正数
     * @return 日期差
     * @since 3.3.1
     */
    public static long between(Date beginDate, Date endDate, DateUnit unit, boolean isAbs) {
        return DateUtil.between(beginDate, endDate, unit, isAbs);
    }

    /**
     * 创建日期范围生成器
     * 如:
     * DateField.MONTH 可以获取start和end之间的月份列表
     * DateField.DAY_OF_MONTH 可以获取start和end之间的日期列表
     * DateField.HOUR_OF_DAY 可以获取start和end之间的小时列表
     * @param start 起始日期时间
     * @param end   结束日期时间
     * @param unit  步进单位, 如:DateField.MONTH、DateField.DAY_OF_MONTH、DateField.HOUR_OF_DAY
     * @return List<Date>
     */
    public static List<Date> rangeToList(Date start, Date end, final DateField unit) {
        List<DateTime> dates = DateUtil.rangeToList(start, end, unit);
        return dates.stream().map(s -> (Date) s).collect(Collectors.toList());
    }

}
